package org.fintan.make.utils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.fintan.make.entity.User;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.impl.DefaultJwsHeader;
import io.jsonwebtoken.impl.TextCodec;
import tk.mybatis.mapper.util.StringUtil;

@Component
public class JWTUtil {

	@Value("${jwt.secret}")
	private String secret;

	// 默认加密方式
	private static final SignatureAlgorithm SIGNATUREALGORITHM = SignatureAlgorithm.HS256;

	// token中用户信息的key
	private static final String USER_INFO_KEY = "userInfo";

	/***
	 * 创建jwt header
	 * 
	 * @param signatureAlgorithm:加密方式
	 * @return
	 */
	public JwsHeader getJWTHeader(SignatureAlgorithm signatureAlgorithm) {
		if (signatureAlgorithm == null)
			signatureAlgorithm = SIGNATUREALGORITHM;
		JwsHeader jwsHeader = new DefaultJwsHeader();
		jwsHeader.setAlgorithm(signatureAlgorithm.getValue());
		jwsHeader.setType(Header.JWT_TYPE);
		return jwsHeader;
	}

	// public static void main(String[] args) {
	// System.out.println(getJWTHeader().toString());
	// String header = getBase64EncodedKey(getJWTHeader().toString());
	// System.out.println(header);
	// Map<String, Object> claims = new HashMap<String, Object>();
	// claims.put("name", "123");
	// claims.put("age", "18");
	// User user = new User();
	// user.setUserName("123");
	// user.setAge(18);
	// String us = createJWT(getJWTHeader(), getDefaultClaims(), user);
	// System.out.println(us);
	// Claims claims = parseJWT(us);
	// System.out.println(claims.get("userName"));
	//
	// }

	/***
	 *
	 * @return
	 */
	public JwsHeader getJWTHeader() {
		return getJWTHeader(null);
	}

	/***
	 *
	 * 创建jwt 指定头信息 指定申明
	 * 
	 * @param header
	 * @param claims
	 * @param userModel
	 * @return
	 */
	public String createJWT(Header header, Claims claims, User user) {
		JwtBuilder builder = Jwts.builder();
		builder.setHeaderParams(header);

		if (user != null) {
			claims.put("userName", user.getUserName());
			claims.put("id", user.getId());
		}
		// 设置自定义申明
		if (claims != null && !claims.isEmpty()) {
			builder.setClaims(claims);
		}
		builder.signWith(SIGNATUREALGORITHM, getBase64EncodedKey(getTokenSecret()));
		return builder.compact();
	}

	/***
	 * 指定加密方式指定申明
	 * 
	 * @param signatureAlgorithm
	 * @param claims
	 * @param userModel
	 * @return
	 */
	public String createJWT(SignatureAlgorithm signatureAlgorithm, Claims claims, User user) {
		return createJWT(getJWTHeader(signatureAlgorithm), claims, user);
	}

	/***
	 * 指定加密方式
	 * 
	 * @param signatureAlgorithm
	 * @param userModel
	 * @return
	 */
	public String createJWT(SignatureAlgorithm signatureAlgorithm, User user) {
		return createJWT(signatureAlgorithm, getDefaultClaims(), user);
	}

	/***
	 * 使用默认加密方式,指定申明
	 * 
	 * @param claims
	 * @param userModel
	 * @return
	 */
	public String createJWT(Claims claims, User user) {
		return createJWT(getJWTHeader(), claims, user);
	}

	/***
	 * 使用默认申明,默认加密方式创建jwt
	 * 
	 * @param userModel
	 * @return
	 */
	public String createJWT(User user) {
		return createJWT(getDefaultClaims(), user);
	}

	/***
	 * 获取申明
	 * 
	 * @param exp:过期时间
	 * @param nbfDate:生效时间
	 * @param iss:签发者
	 * @param sub:面向用户
	 * @param aud:接收的一方
	 * @return
	 */
	public Claims getClaims(Date issAt, Date exp, Date nbfDate, String iss, String sub, String aud) {
		Claims claims = new DefaultClaims();
		// 设置签发时间
		if (issAt != null) {
			claims.setIssuedAt(new Date());
		}
		// 设置过期时间
		if (exp != null) {
			claims.setExpiration(exp);
		}
		// 设置生效时间
		if (nbfDate != null) {
			claims.setNotBefore(nbfDate);
		}
		// 设置签发者
		if (!StringUtil.isEmpty(iss)) {
			claims.setIssuer(iss);
		}
		// 设置该token面向的用户
		if (StringUtil.isEmpty(sub)) {
			claims.setSubject(sub);
		}
		// 设置接收该token的一方
		if (StringUtil.isEmpty(aud)) {
			claims.setAudience(aud);
		}
		return claims;
	}

	/**
	 * 指定过期日期
	 * 
	 * @param expDate
	 * @return
	 */
	public Claims getClaims(Date expDate) {
		return getClaims(new Date(), expDate, null, null, null, null);
	}

	/*
	 * public static Date generateExpirationDate() { return new
	 * Date(System.currentTimeMillis() + 10 * 1000); }
	 */

	/***
	 * 获取默认申明
	 * 
	 * @return
	 */
	public Claims getDefaultClaims() {
		Date now = new Date();
		// 获取配置的默认过期时间  1天
		Integer expDays = 1;// DZPropertyConfigurer.getContextProperty(Constants.DZ_TOKEN_EXP_DAY,
								// Integer.class);
		Date expDate = null;
		if (expDays != null && expDays.intValue() > 0) {
			expDate = DateUtils.addHours(now, expDays);
		}
		return getClaims(now, expDate, null, null, null, null);
	}
/*
	public static void main(String[] args) {
		Date now = new Date();
		Integer expDays = 1;// DZPropertyConfigurer.getContextProperty(Constants.DZ_TOKEN_EXP_DAY,
		// Integer.class);
		Date expDate = null;
		if (expDays != null && expDays.intValue() > 0) {
			expDate = DateUtils.addDays(now, expDays.intValue());
		}
		
		System.out.println(DateUtil.getDateString(expDate));
	}
*/
	/**
	 * 解密 jwt
	 * 
	 * @param jwt
	 * @return
	 * @throws Exception
	 */
	public Claims parseJWT(String jwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
			SignatureException, IllegalArgumentException {
		Claims claims = Jwts.parser().setSigningKey(getBase64EncodedKey(getTokenSecret())).parseClaimsJws(jwt)
				.getBody();
		return claims;
	}

	/***
	 * 获取系统配置的token签名秘钥
	 * 
	 * @return
	 */
	public String getTokenSecret() {
		System.out.println(secret);
		return this.secret;
	}

	/***
	 * 将secret 用BASE64加密
	 * 
	 * @return
	 */
	public String getBase64EncodedKey(String secret) {

		return secret == null ? null : TextCodec.BASE64.encode(secret);
	}

}
